home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Jumpstart / Multimedia Microsoft Jumpstart Version 1.1a (Microsoft).BIN / develpmt / source / cropdib / cropdib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-12  |  17.2 KB  |  583 lines

  1. /* Microsoft Multimedia Systems Sample Code Library
  2.  *
  3.  * CropDIB.c is a Windows with Multimedia application that crops a
  4.  * series of DIBs. It uses the DIB driver; although this is the only 
  5.  * multimedia component that it demonstrates, the DIB.C module contains
  6.  * many useful functions for working with DIBs and palettes.
  7.  *
  8.  * This application crops and "brighten" (add a specified increment to
  9.  * the palette entries) a series of DIBs. 
  10.  *
  11.  * If an input "pattern" is specified, it opens a series of input files; 
  12.  * otherwise, it opens only the specified filename. From each input file,
  13.  * it can read one or a series of DIBs.
  14.  *
  15.  * If an output "pattern" is specified, it writes the DIBs to a series 
  16.  * of output files; otherwise, it writes all the DIBs to the single
  17.  * specified filename.
  18.  *
  19.  * Demonstrates:
  20.  *         Use of DIB Driver
  21.  *         Direct manipulation of DIB pixel data
  22.  *         Direct manipulation of DIB palette data
  23.  *         Cacheing of Driver to avoid re-load
  24.  *
  25.  * (C) Copyright Microsoft Corp. 1991.  All rights reserved.
  26.  *
  27.  * You have a royalty-free right to use, modify, reproduce and 
  28.  * distribute the Sample Files (and/or any modified version) in 
  29.  * any way you find useful, provided that you agree that 
  30.  * Microsoft has no warranty obligations or liability for any 
  31.  * Sample Application Files which are modified.
  32.  *
  33.  */
  34.  
  35. #include <windows.h>
  36. #include <stdlib.h>
  37. #include "cropdib.h"
  38. #include "dib.h"
  39.  
  40.  
  41. /* Globals */
  42. char    gszAppName[] = "CropDIB";       // For title bar etc.
  43. HANDLE  ghInst;                         // Program instance handle
  44.  
  45.  
  46. /* Wait cursor */
  47. static HCURSOR  ghcurSave;              // Previous cursor
  48. int      giCurSave = 0;                 // Use count variable for StartWait()
  49. #define StartWait()     ((giCurSave++ == 0)     \
  50.     ? (ghcurSave = SetCursor(LoadCursor(NULL, IDC_WAIT))) : 0)
  51. #define EndWait()       ((--giCurSave == 0)     \
  52.     ? SetCursor(ghcurSave) : 0)
  53.  
  54.  
  55. /* prototypes */
  56. int  ErrMsg (HWND hwnd, int idsfmt, ...);
  57. BOOL NEAR PASCAL DoCrop(HWND hwnd);
  58. GLOBALHANDLE NEAR PASCAL CropDIB(GLOBALHANDLE hdibOld,
  59.     int xCrop, int yCrop, int wCrop, int hCrop);
  60. void NEAR PASCAL BrightenDIB(GLOBALHANDLE hdib, int iBrightenBy);
  61. BOOL NEAR PASCAL IsPattern(LPSTR sz);
  62. int PASCAL WinMain(HANDLE hInst, HANDLE hPrev, LPSTR lpszCmdLine, int iCmdShow);
  63. BOOL FAR PASCAL AboutDlgProc(HWND hwnd, unsigned wMsg,
  64.     WORD wParam, LONG lParam);
  65. BOOL FAR PASCAL CropDIBDlgProc(HWND hwnd, unsigned wMsg,
  66.     WORD wParam, LONG lParam);
  67.  
  68.  
  69. /* DoCrop(hwnd)
  70.  *
  71.  * Perform cropping operation, using information in controls in
  72.  * dialog box <hwnd>.
  73.  */
  74. BOOL NEAR PASCAL DoCrop(
  75.     HWND hwnd)                      // Dialog-box window handle
  76. {
  77.     BOOL  fOK = FALSE;
  78.     char  achInFilePat[_MAX_PATH];  // Input file or pattern
  79.     char  achOutFilePat[_MAX_PATH]; // Output file or pattern
  80.     char  achInFile[_MAX_PATH];     // Actual input file name
  81.     char  achOutFile[_MAX_PATH];    // Actual output file name
  82.     int   fhIn = -1;                // Input file handle (or -1)
  83.     int   fhOut = -1;               // Output file handle (or -1)
  84.  
  85.     int   xCrop, yCrop;             // Crop rectangle location
  86.     int   wCrop, hCrop;             // Crop rectangle size
  87.     int   iBrightenBy;              // Brighten by how much?
  88.  
  89.     int   iInFrameNo;               // Input frame number
  90.     int   iOutFrameNo;              // Output frame number
  91.     GLOBALHANDLE hdib = NULL;       // Memory DIB (or NULL)
  92.     BOOL  fFirstDIBRead;            // Make file has at least 1 DIB
  93.  
  94.     LPSTR szCopyCrop;               // "Copying" or "Cropping"
  95.     char  ach[_MAX_PATH + 50];      // Status message buffer
  96.  
  97.     /* Read parameters from dialog box fields.
  98.      */
  99.     achInFilePat[0] == 0;
  100.     GetDlgItemText(hwnd, ID_INPUTFILEEDIT, 
  101.         achInFilePat, sizeof(achInFilePat));
  102.  
  103.     achOutFilePat[0] == 0;
  104.     GetDlgItemText(hwnd, ID_OUTPUTFILEEDIT,
  105.         achOutFilePat, sizeof(achInFilePat));
  106.  
  107.     xCrop = GetDlgItemInt(hwnd, ID_XEDIT, NULL, TRUE);
  108.     yCrop = GetDlgItemInt(hwnd, ID_YEDIT, NULL, TRUE);
  109.     wCrop = GetDlgItemInt(hwnd, ID_WEDIT, NULL, TRUE);
  110.     hCrop = GetDlgItemInt(hwnd, ID_HEDIT, NULL, TRUE);
  111.  
  112.     iBrightenBy = GetDlgItemInt(hwnd, ID_BRIGHTEDIT, NULL, TRUE);
  113.  
  114.     szCopyCrop = ((wCrop == 0) && (hCrop == 0)) ? "Copying" : "Cropping";
  115.  
  116.     /* Open input and output files (if no pattern specified).
  117.      */
  118.     if(!IsPattern(achInFilePat))
  119.     {
  120.         fhIn = _lopen(achInFilePat, READ);
  121.         if(fhIn < 0)
  122.         {
  123.             Error1(hwnd, IDS_CANTOPENFILE, (LPSTR)achInFilePat);
  124.             goto DoCrop_EXIT;
  125.         }
  126.         lstrcpy(achInFile, achInFilePat);
  127.     }
  128.  
  129.     if(!IsPattern(achOutFilePat))
  130.     {
  131.         fhOut = _lcreat(achOutFilePat, NULL);
  132.         if(fhOut < 0)
  133.         {
  134.             Error1(hwnd, IDS_CANTOPENFILE, (LPSTR)achOutFilePat);
  135.             goto DoCrop_EXIT;
  136.         }
  137.         lstrcpy(achOutFile, achOutFilePat);
  138.     }
  139.  
  140.     /* For each input file, process all the DIBs in the input file
  141.      */
  142.     iInFrameNo = iOutFrameNo = 0;
  143.     while(TRUE)
  144.     {
  145.         if(IsPattern(achInFilePat))
  146.         {
  147.             wsprintf(achInFile, achInFilePat, iInFrameNo++);
  148.             fhIn = _lopen(achInFile, READ);
  149.             if(fhIn < 0)
  150.             {
  151.                 if(iInFrameNo == 1)
  152.                 {
  153.                     iOutFrameNo++;  // If first open fails, continue; pattern
  154.                     continue;       // may be 1-relative.
  155.                 }                
  156.                 else
  157.                 {
  158.                     break;
  159.                 }
  160.             }
  161.         }
  162.  
  163.         /* For each DIB in input file <fhIn>, write the DIBs into one or
  164.          * more output files.
  165.          */
  166.         fFirstDIBRead = TRUE;
  167.         while(TRUE)
  168.         {
  169.             /* Open a DIB.
  170.              */
  171.             wsprintf(ach, "%s from %s", (LPSTR)szCopyCrop,
  172.                 (LPSTR)achInFile);
  173.             SetDlgItemText(hwnd, ID_STATUSTEXT, ach);
  174.             
  175.             if((hdib = OpenDIB(fhIn)) == NULL)
  176.             {
  177.                 if(fFirstDIBRead)
  178.                 {
  179.                     Error1(hwnd, IDS_ERRORREADING, (LPSTR)achInFile);
  180.                     goto DoCrop_EXIT;
  181.                 }
  182.                 else
  183.                     break;
  184.             }
  185.             fFirstDIBRead = FALSE;
  186.  
  187.             /* Brighten the DIB.
  188.              */
  189.             if(iBrightenBy != 0)
  190.                 BrightenDIB(hdib, iBrightenBy);
  191.  
  192.             /* Crop the DIB.
  193.              */
  194.             if((wCrop != 0) || (hCrop != 0))
  195.             {
  196.                 GLOBALHANDLE    hdibNew;
  197.  
  198.                 /* Preserve hdib in case CropDib fails.
  199.                  */
  200.                 hdibNew = CropDIB(hdib, xCrop, yCrop, wCrop, hCrop);
  201.                 if(hdibNew == NULL)
  202.                     goto DoCrop_EXIT;
  203.                 hdib = hdibNew;
  204.             }
  205.  
  206.             /* If there's an output file pattern, open the
  207.              * next output file; otherwise we append the DIB to the
  208.              * already open output file.
  209.              */
  210.             if(IsPattern(achOutFilePat))
  211.             {
  212.                 wsprintf(achOutFile, achOutFilePat,
  213.                     iOutFrameNo++);
  214.                 fhOut = _lcreat(achOutFile, NULL);
  215.                 if(fhOut < 0)
  216.                 {
  217.                     Error1(hwnd, IDS_CANTOPENFILE,
  218.                         (LPSTR)achOutFile);
  219.                     goto DoCrop_EXIT;
  220.                 }
  221.             }
  222.  
  223.             /* Write the DIB to <fhOut>.
  224.              */
  225.             wsprintf(ach, "%s from %s to %s", (LPSTR)szCopyCrop,
  226.                 (LPSTR)achInFile, (LPSTR)achOutFile);
  227.             SetDlgItemText(hwnd, ID_STATUSTEXT, ach);
  228.  
  229.             if(!WriteDIB(fhOut, hdib))
  230.             {
  231.                 Error1(hwnd, IDS_ERRORREADING, (LPSTR)achInFile);
  232.                 goto DoCrop_EXIT;
  233.             }
  234.  
  235.             GlobalFree(hdib), hdib = NULL;
  236.  
  237.             /* Close the output file (if specified from a pattern).
  238.              */
  239.             if(IsPattern(achOutFilePat))
  240.             {
  241.                 _lclose(fhOut);
  242.                 fhOut = -1;
  243.             }
  244.         }
  245.  
  246.         if(IsPattern(achInFilePat))
  247.         {
  248.             _lclose(fhIn);
  249.             fhIn = -1;
  250.         }
  251.         else
  252.             break;
  253.     }
  254.  
  255.     fOK = TRUE;
  256.  
  257. DoCrop_EXIT:
  258.  
  259.     if(fhIn >= 0)
  260.     {
  261.         _lclose(fhIn);
  262.         fhIn = -1;
  263.     }
  264.  
  265.     if(fhOut >= 0)
  266.     {
  267.         _lclose(fhOut);
  268.         fhOut = -1;
  269.     }
  270.  
  271.     if(hdib != NULL)
  272.     {
  273.         GlobalFree(hdib);
  274.         hdib = NULL;
  275.     }
  276.     return fOK;
  277. }
  278.  
  279.  
  280. /* hdibNew = CropDIB(hdibOld, xCrop, yCrop, wCrop, hCrop)
  281.  *
  282.  * Crops the specified rectangle from memory DIB <hdibOld> and returns
  283.  * a new memory DIB containing the cropped portion of the original DIB.
  284.  * If successful, it frees the original DIB (hdibOld).
  285.  *
  286.  * On failure, the function displays a message and returns NULL. <hdibOld> 
  287.  * is not freed.
  288.  */
  289. GLOBALHANDLE NEAR PASCAL CropDIB(
  290.     GLOBALHANDLE hdibOld,                   // DIB to crop
  291.     int xCrop,
  292.     int yCrop,                              // Crop origin
  293.     int wCrop,
  294.     int hCrop)                              // Crop extents
  295. {
  296.     BOOL               fOK =     FALSE;
  297.     GLOBALHANDLE       hdibNew = NULL;
  298.     LPBITMAPINFOHEADER lpbiOld = NULL;
  299.     BITMAPINFOHEADER   bihOld;
  300.     BYTE huge *        pBitsOld;
  301.  
  302.     LPBITMAPINFOHEADER lpbiNew = NULL;
  303.     HDC                hdcNew =  NULL;
  304.  
  305.     /* Create a DIB to hold the cropped portion of the <hdibOld> 
  306.      */
  307.     hdibNew = CreateDib(hdibOld, wCrop, hCrop);
  308.     if(hdibNew == NULL)
  309.     {
  310.         Error(NULL, IDS_OUTOFMEMORY);
  311.         goto CropDIB_EXIT;
  312.     }
  313.  
  314.     /* Lock both DIBs 
  315.      */
  316.     lpbiOld = (LPBITMAPINFOHEADER)GlobalLock(hdibOld);
  317.     lpbiNew = (LPBITMAPINFOHEADER)GlobalLock(hdibNew);
  318.  
  319.     pBitsOld = (LPSTR)lpbiOld + (WORD)lpbiOld->biSize + PaletteSize(lpbiOld);
  320.  
  321.     /* Get a DC onto the new DIB.
  322.      */
  323.     hdcNew = CreateDC("DIB", NULL, NULL, (LPSTR)lpbiNew);
  324.     if(hdcNew == NULL)
  325.     {
  326.         if((lpbiOld->biBitCount == 24) || (lpbiOld->biCompression != BI_RGB))
  327.         {
  328.             Error(NULL, IDS_FORMATNOTSUPPORTED);
  329.         }
  330.         else
  331.         {
  332.             Error(NULL, IDS_CANTLOADDIBDRV);
  333.         }
  334.         goto CropDIB_EXIT;
  335.     }
  336.  
  337.     /* Copy from the old DIB to the new DIB. Get the BITMAPINFOHEADER
  338.      * values and calculate the Y-origin of the crop area (the bitmap
  339.      * origin is at the lower-left corner).
  340.      */
  341.     DibInfo(hdibOld, &bihOld);              // Get BITMAPINFOHEADER
  342.  
  343.     yCrop = (int)bihOld.biHeight - (yCrop + hCrop);
  344.  
  345.     StretchDIBits(  hdcNew,                 // Destination DC
  346.                     0, 0,                   // Destination origin
  347.                     wCrop, hCrop,           // Destination width & height
  348.                     xCrop, yCrop,           // Source origin
  349.                     wCrop, hCrop,           // Source width & height
  350.                     pBitsOld,               // Bitmap bits
  351.                     (LPBITMAPINFO)lpbiOld,  // Bitmap header
  352.                     DIB_RGB_COLORS,         // Meaning of palette entries
  353.                     SRCCOPY);               // ROP
  354.     
  355.     fOK = TRUE;
  356.  
  357. CropDIB_EXIT:
  358.  
  359.     if(hdcNew != NULL)
  360.         DeleteDC(hdcNew);
  361.     if(lpbiOld != NULL)
  362.         GlobalUnlock(hdibOld);
  363.     if(lpbiNew != NULL)
  364.         GlobalUnlock(hdibNew);
  365.  
  366.     if(fOK)
  367.     {
  368.         /* Successful -- delete <hdibOld> and return <hdibNew> 
  369.          */
  370.         GlobalFree(hdibOld);
  371.         return hdibNew;
  372.     }
  373.     else
  374.         return NULL;
  375. }
  376.  
  377.  
  378. /* BrightenDIB(hdib, iBrightenBy)
  379.  *
  380.  * Brighten <hdib> by adding <iBrightenBy> to each component of its palette.
  381.  */
  382. void NEAR PASCAL BrightenDIB(
  383.     GLOBALHANDLE    hdib,                   // DIB to brighten
  384.     int      iBrightenBy )                  // How much brightness to add
  385. {
  386.     LPBITMAPINFOHEADER lpbi;
  387.     RGBQUAD FAR *prgb;
  388.     int cPalEntries;
  389.     int r, g, b;
  390.  
  391.  
  392.     /* Lock the DIB.
  393.      */
  394.     if((lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib)) == NULL)
  395.         return;
  396.  
  397.     prgb = (RGBQUAD FAR *)((LPBYTE)lpbi + lpbi->biSize);
  398.  
  399.     cPalEntries = (int)lpbi->biClrUsed;
  400.  
  401.     while(cPalEntries > 0)
  402.     {
  403.         r = (int)prgb->rgbRed   + iBrightenBy;
  404.         g = (int)prgb->rgbGreen + iBrightenBy;
  405.         b = (int)prgb->rgbBlue  + iBrightenBy;
  406.  
  407.         prgb->rgbRed =   (BYTE)max(0, min(r, 255));
  408.         prgb->rgbGreen = (BYTE)max(0, min(g, 255));
  409.         prgb->rgbBlue =  (BYTE)max(0, min(b, 255));
  410.  
  411.         prgb++;
  412.         cPalEntries--;
  413.     }
  414.     GlobalUnlock(hdib);
  415. }
  416.  
  417.  
  418. /* fPattern = IsPattern(sz)
  419.  *
  420.  * Return TRUE if <sz> is a numbered file pattern, e.g. "frm%02.dib".
  421.  */
  422. BOOL NEAR PASCAL IsPattern(
  423.     LPSTR sz)
  424. {
  425.     while(*sz != 0)
  426.     {
  427.         if(*sz++ == '%')
  428.             return TRUE;
  429.     }
  430.  
  431.     return FALSE;
  432. }
  433.  
  434.  
  435. /* WinMain(hInst, hPrev, lpszCmdLine, cmdShow)
  436.  * 
  437.  * The main procedure for the App.
  438.  */
  439. int PASCAL WinMain(
  440.     HANDLE  hInst,              // Instance handle of current instance
  441.     HANDLE  hPrev,              // Instance handle of previous instance
  442.     LPSTR   lpszCmdLine,        // Null-terminated command line
  443.     int     iCmdShow )          // How window should be initially displayed
  444. {
  445.     FARPROC  fpfn;
  446.  
  447.     /* Save instance handle for dialog boxes */
  448.     ghInst = hInst;
  449.  
  450.  
  451.     /* Display CropDIB dialog box */
  452.  
  453.     fpfn = MakeProcInstance((FARPROC)CropDIBDlgProc, ghInst);
  454.     DialogBox(ghInst, MAKEINTRESOURCE(CROPDIBBOX), NULL, fpfn);
  455.     FreeProcInstance(fpfn);
  456.  
  457.     return TRUE;
  458. }
  459.  
  460.  
  461. /* AboutDlgProc(hwnd, wMsg, wParam, lParam)
  462.  *
  463.  * This function handles messages belonging to the "About" dialog box.
  464.  * The only message that it looks for is WM_COMMAND, indicating the user
  465.  * has pressed the "OK" button.  When this happens, it takes down
  466.  * the dialog box.
  467.  */
  468. BOOL FAR PASCAL AboutDlgProc(
  469.     HWND     hwnd,              // Window handle of "about" dialog box
  470.     unsigned wMsg,              // Message number
  471.     WORD     wParam,            // Message-dependent parameter
  472.     LONG     lParam )           // Message-dependent parameter
  473. {
  474.     switch (wMsg)
  475.     {
  476.         case WM_INITDIALOG:
  477.             return TRUE;
  478.  
  479.         case WM_COMMAND:
  480.             if(wParam == IDOK)
  481.                 EndDialog(hwnd, TRUE);
  482.             break;
  483.     }
  484.     return FALSE;
  485. }
  486.  
  487.  
  488. /* CropDIBDlgProc(hwnd, wMsg, wParam, lParam)
  489.  *
  490.  * This function handles messages belonging to the "CropDIB" dialog box.
  491.  */
  492. BOOL FAR PASCAL CropDIBDlgProc(
  493.     HWND     hwnd,              // Window handle of "about" dialog box
  494.     unsigned wMsg,              // Message number
  495.     WORD     wParam,            // Message-dependent parameter
  496.     LONG     lParam )           // Message-dependent parameter
  497. {
  498.     FARPROC  fpfn;
  499.     HMENU    hmenuSystem;       // Handle to system menu
  500.     HDC      hdcCache;
  501.  
  502.     switch (wMsg)
  503.     {
  504.         case WM_INITDIALOG:
  505.  
  506.             /* append "About" menu item to system menu */
  507.             hmenuSystem = GetSystemMenu(hwnd, FALSE);
  508.             AppendMenu(hmenuSystem, MF_SEPARATOR, 0, NULL);
  509.             AppendMenu(hmenuSystem, MF_STRING, IDM_ABOUT,
  510.                 "&About CropDIB...");
  511.             return TRUE;
  512.  
  513.         case WM_SYSCOMMAND:
  514.             switch (wParam)
  515.             {
  516.                 case IDM_ABOUT:
  517.  
  518.                     /* request to display "About" dialog box */
  519.                     fpfn = MakeProcInstance((FARPROC) AboutDlgProc, ghInst);
  520.                     DialogBox(ghInst, MAKEINTRESOURCE(ABOUTBOX),
  521.                                 hwnd, fpfn);
  522.                     FreeProcInstance(fpfn);
  523.  
  524.                     break;
  525.             }
  526.             break;
  527.  
  528.         case WM_COMMAND:
  529.  
  530.             switch (wParam)
  531.             {
  532.                 case IDOK:              // "Begin"
  533.  
  534.                     StartWait();
  535.  
  536.                     /* Cache the DIB driver here so we don't need to reload
  537.                      * it every time we do a crop.
  538.                      */
  539.                     hdcCache = CreateDC("DIB", NULL, NULL, NULL);
  540.                     if(hdcCache == NULL)
  541.                     {
  542.                         Error(hwnd, IDS_CANTLOADDIBDRV);
  543.                         EndWait();
  544.                         EndDialog(hwnd, FALSE);
  545.                         break;
  546.                     }
  547.                     DoCrop(hwnd);
  548.  
  549.                     /* Clear the status text control */
  550.                     SetDlgItemText(hwnd, ID_STATUSTEXT, "");
  551.  
  552.                     /* Get rid of the cache */
  553.                     DeleteDC(hdcCache);
  554.  
  555.                     EndWait();
  556.                     break;
  557.  
  558.                 case IDCANCEL:          // "Done"
  559.  
  560.                     EndDialog(hwnd, TRUE);
  561.                     break;
  562.             }
  563.             break;
  564.     }
  565.     return FALSE;
  566. }
  567.  
  568. /* ErrMsg(hWnd, iszfmt, ...)
  569.  *
  570.  * Displays a message box with the formatted string supplied in <iszfmt>.
  571.  */
  572. int ErrMsg(HWND hwnd, int iszfmt, ...)
  573. {
  574.     char    ach[128];
  575.     char    sz[80];
  576.     
  577.     LoadString(ghInst,iszfmt,sz,sizeof(sz));
  578.  
  579.     wvsprintf (ach, sz, (LPSTR)(&iszfmt + 1));     // Format the string 
  580.     MessageBox(hwnd, ach, NULL, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
  581.     return FALSE;
  582. }
  583.